home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / lang / c++-part2 / 17732 < prev    next >
Encoding:
Internet Message Format  |  1996-08-05  |  6.7 KB

  1. Path: ivan.iecc.com!not-for-mail
  2. From: mw@ipx2.rz.uni-mannheim.de (Marc Wachowitz)
  3. Newsgroups: comp.compilers,comp.lang.c++
  4. Subject: Re: Parsing C++ headers?
  5. Date: 16 Apr 1996 22:25:33 -0400
  6. Organization: Compilers Central
  7. Sender: johnl@iecc.com
  8. Approved: compilers@ivan.iecc.com
  9. Message-ID: <96-04-096@comp.compilers>
  10. References: <96-04-033@comp.compilers>
  11. NNTP-Posting-Host: localhost.iecc.com
  12. Keywords: C++, yacc, parse
  13.  
  14. John Mitchell (104316.1514@CompuServe.COM) wrote:
  15. > I want to parse C++ header files, and extract information about the
  16. > contained classes and their interface. A yacc-able grammar for this
  17. > type of problem ( or superset of it, as for compilation) would be a
  18. > great help.
  19.  
  20. You might also look at ftp://ftp.csl.sri.com/pub/dodd/btyacc.tar.gz -
  21. the README file is appended below. Using a relatively "understandable"
  22. (as far as one can say so for C++ ;-) grammar - such as from the ARM,
  23. or the latest working draft - and paying a limited performance penalty
  24. may be preferrable to a possibly somewhat faster "patchwork"-parser
  25. recognizing constructs as early as possible.
  26.  
  27.              -- Marc Wachowitz <mw@ipx2.rz.uni-mannheim.de>
  28.  
  29.  
  30.  
  31. BTYACC -- backtracking yacc.
  32.  
  33. BTYACC was created by Chris Dodd using ideas from many places and lots
  34. of code from the Berkeley Yacc distribution, which is a public domain
  35. yacc clone put together by the good folks at Berkeley.  This code is
  36. distributed with NO WARRANTEE and is public domain.  It is certain to
  37. contain bugs, which you should report to:
  38.     dodd@csl.sri.com
  39.  
  40. See the README.BYACC, NEW_FEATURES, and ACKNOWLEDGEMENTS files for more
  41. about Berkeley Yacc and other sources of info.
  42.  
  43. BTYACC is a modified version of yacc that supports automatic
  44. backtracking and semantic disambiguation to parse ambiguous grammars,
  45. as well as syntactic sugar for inherited attributes (which tend to
  46. introduce conflicts).  Whenever a btyacc generated parser runs into a
  47. shift-reduce or reduce-reduce error in the parse table, it remembers
  48. the current parse point (yacc stack and input stream state), and goes
  49. into trial parse mode.  It then continues parsing, ignoring most rule
  50. actions.  If it runs into an error (either through the parse table or
  51. through an action calling YYERROR), it backtracks to the most recent
  52. conflict point and tries a different alternative.  If it finds a
  53. successful parse (reaches the end of the input or an action calls
  54. YYVALID), it backtracks to the point where it first entered trial
  55. parse mode, and continues with a full parse (executing all actions),
  56. following the path of the successful trial.
  57.  
  58. Actions in btyacc come in two flavors -- {}-actions, which are only
  59. executed when not in trial mode, and []-actions which are executed
  60. regardless of mode.  There are also inherited attributes, which look
  61. like arguments (they're enclosed in `()') and act like []-actions.
  62.  
  63. What this buys you:
  64.  
  65. * No more lexer feedback hack.  In yacc grammars for C, a standard
  66. hack, know as the `lexer feedback hack' is used to find typedef names.
  67. The lexer uses semantic information to decide if any given identifier
  68. is a typedef-name or not and returns a special token.  With btyacc,
  69. you no longer need to do this; the lexer should just always return an
  70. identifier.  The btyacc grammar then needs a rule of the form:
  71.  
  72. typename: ID [ if (!IsTypeName(LookupId($1))) YYERROR; ]
  73.  
  74. While the hack works adequately well for parsing C, it becomes a
  75. nightmare when you try to parse something like C++, where treating
  76. an ID as a typedef becomes heavily dependent on context.
  77.  
  78. * Easy disambiguation via simple ordering.  Btyacc runs its trials via
  79. the rule ``try shifting first, then try reducing by the order that the
  80. conflicting rules appear in the input file''.  This means you can deal
  81. with semantic a disambiguation rule like:
  82.     [1] If it looks like a declaration it is, otherwise
  83.     [2] If it looks like an expression it is, otherwise
  84.     [3] it is a syntax error
  85.         [Ellis & Stroustrup, Annotated C++ Reference Manual, p93]
  86.  
  87. To deal with this, you need only put all the rules for declarations
  88. before the rules for expressions in the grammar file.
  89.  
  90. * No extra cost if don't use it.  Backtracking is only triggered when
  91. the parse hits a shift/reduce or reduce/reduce conflict in the table.
  92. If you have no conflicts in your grammar, there's no extra cost, other
  93. than some extra code which will never be invoked.
  94.  
  95. * C++ and ANSI C compatible parsers.  The parsers produced by btyacc
  96. can be compiled with C++ correctly.  If you `#define' YYSTYPE to be
  97. some C++ type with constructor and destructor, everything will work
  98. fine.  My favorite is `#define YYSTYPE SmartPointer', where
  99. SmartPointer is a smart pointer type that does garbage collection on
  100. the pointed to objects.
  101.  
  102. BTYACC was originally written to make it easy to write a C++ parser
  103. (my goal was to be able to use the grammar out of the back of the ARM
  104. with as few modifications as possible).  Anyone who has ever looked at
  105. Jim Roskind's public domain C++ yacc grammar, or the yacc-based
  106. grammar used in g++ knows how difficult this is.  BTYACC is very
  107. useful for parsing any ambiguous grammar, particularly ones that come
  108. from trying to merge two (or more) complete grammars.
  109.  
  110. Inherited attributes in btyacc:
  111.  
  112. Inherited attributes look a lot like function arguments to non-terminals,
  113. which is what they end up being in a recursive descent parser, but NOT
  114. how they're implemented in btyacc.  Basically they're just syntactic
  115. sugar for embedded semantic actions and $0, $-1, ... in normal yacc.
  116. btyacc gives you two big advantages besides just the syntax:
  117.     1. it does type checking on the inherited attributes, so you don't
  118.        have to specify $<type>0 and makes sure you give the correct`
  119.        number of arguments (inherited attributes) to every use of a
  120.        non-terminal.
  121.     2. It `collapses' identical actions from that are produced from
  122.        inherited attributes.  This eliminates many potential reduce-reduce
  123.        conflicts arrising from the inherited attributes.
  124.  
  125. You use inherited attributes by declaring the types of the attributes
  126. in the preamble with a type declaration and declaring names of the
  127. attributes on the lhs of the yacc rule.  You can of course have more
  128. than one rule with the same rhs, and you can even give them different
  129. names in each, but the type and number must be the same.
  130.  
  131. Here's a small example:
  132. %type <t1> lhs(<t1>, <t2>)    /* lhs takes two inherited attributes */
  133.        stuff(<t1>, <t2>)
  134. %%
  135. lhs($i1, $i2) : { $$ = $i1 }
  136.           | lhs($i1, $i2) stuff($1,$i2) { $$ = $2; }
  137.  
  138. This is roughly equivalent to the following yacc code:
  139. lhs : { $$ = $<t1>-1; }
  140.     | lhs [ $<t1>$ = $1; ] [ $<t2>$ = $<t2>0; ] stuff { $$ = $4; }
  141.     ;
  142.  
  143. See the file `test/t2.y' for a longer and more complete example.
  144. At the current time, the start symbol cannot have any arguments.
  145. --
  146. Send compilers articles to compilers@iecc.com,
  147. meta-mail to compilers-request@iecc.com.
  148.